package top.yvyan.guettable.service.fetch;

import static java.lang.Integer.parseInt;
import static java.lang.Math.max;

import android.content.Context;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import top.yvyan.guettable.Gson.ApplicationOTA;
import top.yvyan.guettable.Gson.ClassList;
import top.yvyan.guettable.Gson.ClassTableNew;
import top.yvyan.guettable.Gson.ExamInfoNew;
import top.yvyan.guettable.Gson.ExamScoreNew;
import top.yvyan.guettable.Gson.LabList;
import top.yvyan.guettable.Gson.LabTableJWT;
import top.yvyan.guettable.Gson.LabTableNew;
import top.yvyan.guettable.Gson.NeedCaptcha;
import top.yvyan.guettable.Gson.ProgramModel;
import top.yvyan.guettable.Gson.Semester;
import top.yvyan.guettable.Gson.StudentInfoNew;
import top.yvyan.guettable.Http.HttpConnectionAndCode;
import top.yvyan.guettable.bean.CourseBean;
import top.yvyan.guettable.bean.ExamBean;
import top.yvyan.guettable.bean.SelectedCourseBean;
import top.yvyan.guettable.data.GeneralData;
import top.yvyan.guettable.data.TokenData;
import top.yvyan.guettable.util.VPNUrlUtil;

public class StaticService {

  public static boolean checkNeedCaptcha(Context context, String account) {
    try {
      HttpConnectionAndCode checkCaptcha = Net.checkNeedCaptcha(context, account);
      if (checkCaptcha != null && checkCaptcha.resp_code == 200) {
        NeedCaptcha isNeed = new Gson().fromJson(checkCaptcha.content, NeedCaptcha.class);
        return isNeed.isNeed;
      }
    } catch (Exception ignore) {
    }
    return false;
  }

  /**
   * 发送手机验证码
   *
   * @param context   context
   * @param CASCookie CAS Cookie
   * @param account   学号
   * @return Phone Number
   * ERROR0 : 网络错误
   * ERROR1 : 密码错误
   * ERROR2 : 需要使用外网网址进行访问
   * ERROR3 : 验证码发送CD
   */
  public static String reAuth_sendSMSCode(Context context, String account, String CASCookie) {
    HttpConnectionAndCode response = Net.reAuth_sendSMSCode(context, account, CASCookie);
    if (response.code != 0) {
      if (response.code == -5) {
        return "ERROR2";
      }
    } else {
      if (response.content.contains("success")) {
        int PhoneIndex = response.content.indexOf("\"mobile\":\"") + 10;
        return response.content.substring(PhoneIndex, PhoneIndex + 11);
      }
      if (response.content.contains("code_time_fail")) {
        int MessageIndex = response.content.indexOf("\"returnMessage\":\"") + 17;
        String ErrorMessage = response.content.substring(MessageIndex);
        return "ERROR3;" + ErrorMessage.substring(0, ErrorMessage.indexOf("\""));
      }
    }
    return "ERROR0";
  }

  /**
   * 验证手机验证码
   *
   * @param context   context
   * @param CASCookie CAS Cookie
   * @param SMSCode   OTP手机验证码
   * @return 多因素身份验证令牌Cookie
   * ERROR0 : 网络错误
   * ERROR1 : 验证码错误
   * ERROR2 : 需要使用外网网址进行访问
   */
  public static String reAuth_SMSCode(Context context, String SMSCode, String CASCookie) {
    HttpConnectionAndCode response = Net.reAuth_SMSCode(context, SMSCode, CASCookie);
    if (response.code != 0) {
      if (response.code == -5) {
        return "ERROR2";
      }
      return "ERROR0";
    } else {
      if (response.content.contains("reAuth_success")) {
        return response.cookie;
      }
      return "ERROR1";
    }
  }

  /**
   * 获取SSO登录CasCookie
   *
   * @param context   context
   * @param account   学号
   * @param password  密码
   * @param MFACookie MFA Cookie
   * @param TGTToken  TGTToken
   * @return CAS Cookie
   * ERROR0 : 网络错误
   * ERROR1 : 密码错误
   * ERROR2 : 需要使用外网网址进行访问
   * ERROR5 : 2FA Needed
   */
  public static void SSOLoginVPN(Context context, String account, String password, String MFACookie, String VPNToken) {
    Net.getCASTokenVPN(context, account, password, MFACookie, VPNToken);
  }

  /**
   * 获取SSO登录CasCookie
   *
   * @param context   context
   * @param account   学号
   * @param password  密码
   * @param MFACookie MFA Cookie
   * @param TGTToken  TGTToken
   * @return CAS Cookie
   * ERROR0 : 网络错误
   * ERROR1 : 密码错误
   * ERROR2 : 需要使用外网网址进行访问
   * ERROR5 : 2FA Needed
   */
  public static String SSOLogin(Context context, String account, String password, String captcha, String TGTToken, String MFACookie, String SessionCookie) {
    HttpConnectionAndCode response = Net.getCASToken(context, account, password, captcha, TGTToken, MFACookie, SessionCookie);
    if (response.code != 0) {
      if (response.code == 1) {
        String Location = response.c.getHeaderField("location");
        if (Location.contains("reAuthCheck")) {
          return "ERROR5;" + TGTToken + "; " + response.cookie;
        }
        if (MFACookie != null && !MFACookie.isEmpty()) {
          return MFACookie + "; " + TGTToken;
        } else {
          return TGTToken;
        }
      }
      if (response.code == -8) {
        return "ERROR1";
      }
      return "ERROR0";
    } else {
      String Cookie = response.cookie;
      if (Cookie.contains("TGT-")) {
        String Location = response.c.getHeaderField("location");
        if (Location.contains("reAuthCheck")) {
          return "ERROR5;" + Cookie;
        }
        return Cookie;
      } else {
        return "ERROR1";
      }
    }
  }

  /**
   * Port from Golang
   *
   * @param services
   * @param CasCookie
   * @return With Ticket URL AuthURL
   * ERRORNeedlogin needRelogin
   * ERRORNetwork errNetwork
   */
  public static String loginServerBySSO(Context context, String services, String CasCookie) {
    HttpConnectionAndCode response = Net.loginServerBySSO(context, services, CasCookie);
    if (response != null && response.resp_code / 100 == 3 && response.c != null) {
      String Location = response.c.getHeaderField("location");
      if (Location.contains("reAuthCheck")) {
        return "ERRORNeedlogin";
      }
      if (Location.isEmpty()) {
        return "ERRORNetwork";
      }
      return Location;
    }
    if (response != null && response.resp_code / 100 == 2) {
      return "ERRORNeedlogin";
    }
    return "ERRORNetwork";
  }

  public static ApplicationOTA checkOTA(Context context) {
    try {
      HttpConnectionAndCode response = Net.checkOTA(context);
      if (response != null && response.resp_code == 200) {
        return new Gson().fromJson(response.content, ApplicationOTA.class);
      }
    } catch (Exception ignore) {

    }
    return null;
  }

  public static String getWVPNTicket(Context context, String WVPNToken, String target) {
    HttpConnectionAndCode response = Net.getWVPNTicket(context, WVPNToken, target);
    if (response != null && response.resp_code / 100 == 3 && response.c != null) {
      String Location = response.c.getHeaderField("location");
      if (Location.contains("reAuthCheck")) {
        return "ERRORNeedlogin";
      }
      if (Location.isEmpty()) {
        return "ERRORNetwork";
      }
      return Location;
    }
    if (response != null && response.resp_code / 100 == 2) {
      return "ERRORNeedlogin";
    }
    return "ERRORNetwork";
  }

  /**
   * Port from Golang
   *
   * @param context
   * @param services
   * @param CASCookie
   * @param VPNCookie
   * @param networkType
   * @return AuthedCookie
   * ERRORNeedlogin needRelogin
   * ERRORNetwork errNetwork
   */
  public static String authServiceByCas(Context context, String services, String CASCookie, String VPNCookie, TokenData.NetworkType networkType) {
    String authURL = loginServerBySSO(context, services, CASCookie);
    if (authURL.startsWith("ERROR")) {
      return authURL;
    }
    StringBuilder cookie = new StringBuilder();
    String nextURL = VPNUrlUtil.getVPNUrl(authURL, networkType == TokenData.NetworkType.VPN);
    if (networkType == TokenData.NetworkType.WVPN) {
      cookie.append(VPNCookie).append("; ");
    }
    int max_redirect = 8, redirect_count = 0;
    while (true) {
      HttpConnectionAndCode response = Net.authService(context, nextURL, networkType == TokenData.NetworkType.VPN ? VPNCookie : cookie.toString());
      if (response.resp_code / 100 == 3) {
        String Location = response.c.getHeaderField("location");
        if (Location != null) {
          if (Location.contains("authserver")) {
            return "ERRORNeedlogin";
          }
          if (Location.contains("v.guet.edu.cn/login") || networkType == TokenData.NetworkType.VPN && Location.equals("/login")) {
            return "ERRORNeedLogin";
          }
        }
        if (response.cookie != null && !response.cookie.isEmpty()) {
          cookie.append(response.cookie).append("; ");
          nextURL = Location;
          redirect_count++;
          if (redirect_count < max_redirect) continue;
        }
      }
      if (response.cookie != null && !response.cookie.isEmpty()) {
        cookie.append(response.cookie);
      }
      if (networkType == TokenData.NetworkType.WVPN) {
        return cookie.toString().substring(VPNCookie.length() + 2, max(0, cookie.length() - 2));
      } else {
        return cookie.toString().substring(0, max(0, cookie.length() - 2));
      }
    }
  }

  /**
   * 向VPN添加Cookie
   *
   * @param host     域
   * @param path     路径
   * @param cookie   cookie
   * @param VPNToken VPN Token
   * @return 0 成功
   */
  public static int CookieSet(Context context, String host, String path, String cookie, String VPNToken) {
    HttpConnectionAndCode response = Net.CookieSet(context, host, path, cookie, VPNToken);
    if (response.code == 0) {
      if (response.content.contains("success")) {
        return 0;
      }
    }
    return -1;
  }

  /**
   * 获取基本的学生信息
   *
   * @param context context
   * @param cookie  登录后的cookie
   * @return 基本学生信息
   */
  public static StudentInfoNew getStudentInfoNew(Context context, String cookie) {
    try {
      HttpConnectionAndCode studentInfo = Net.studentInfoNew(context, cookie, TokenData.isVPN());
      if (studentInfo.resp_code == 200) {
        Pattern pattern = Pattern.compile("var ?student ?= ?([^;]+);?\n");
        Matcher matcher = pattern.matcher(studentInfo.content);
        if (matcher.find() && matcher.groupCount() >= 1) {
          String studentInfotext = matcher.group(1).replace("'", "\"");
          return new Gson().fromJson(studentInfotext, StudentInfoNew.class);
        }
      }
    } catch (Exception ignored) {
    }
    return null;
  }

  /**
   * 获取理论课程
   *
   * @param context context
   * @param cookie  登录后的cookie
   * @return 理论课程列表
   */
  public static List<CourseBean> getClassNew(Context context, String cookie, int semesterId) {
    try {
      List<CourseBean> courseBeans = new ArrayList<>();
      HttpConnectionAndCode classTable = Net.getClassTableNew(context, semesterId, cookie, TokenData.isVPN());
      if (classTable.resp_code == 200) {
        ClassTableNew table = new Gson().fromJson(classTable.content, ClassTableNew.class);
        ClassTableNew.studentTableVms maintable = table.studentTableVms.get(0);
        List<ClassTableNew.Lesson> lessions = maintable.activities;
        for (ClassTableNew.Lesson lession : lessions) {
          List<CourseBean> coursebeans = lession.toCourseBean(maintable.getCourseCodeToLessonCodeMap());
          courseBeans.addAll(coursebeans);
        }
        if (courseBeans.isEmpty()) {
          return null;
        }
        return courseBeans;
      }
    } catch (Exception ignored) {

    }
    return null;
  }

  /**
   * 获取培养方案模型
   */
  public static ProgramModel getProgramModel(Context context, String cookie) {
    HttpConnectionAndCode programModel = Net.getProgramModel(context, cookie, TokenData.isVPN());
    if (programModel.resp_code != 200) {
      return null;
    }
    ProgramModel programModelRes = null;
    Pattern pattern = Pattern.compile("model.?=.?(.+);$", Pattern.MULTILINE);
    Matcher matcher = pattern.matcher(programModel.content);
    if (matcher.find() && matcher.groupCount() >= 1) {
      String rawData = matcher.group(1).replace("'", "\"");
      programModelRes = new Gson().fromJson(rawData, ProgramModel.class);
    } else {
      return null;
    }
    try {
      pattern = Pattern.compile("学分绩：</strong>.*?<span>(.+?)</span>", Pattern.DOTALL);
      matcher = pattern.matcher(programModel.content);
      if (matcher.find() && matcher.groupCount() >= 1) {
        String rawData = matcher.group(1);
        double credit = Double.parseDouble(rawData);
        if (programModelRes != null) {
          programModelRes.creditFromSystem = credit;
        }
      }
    } catch (Exception ignore) {

    }
    return programModelRes;
  }

  public static Semester querySemester(Context context, String semesterId, String cookie) {
    HttpConnectionAndCode semesterInfo = Net.querySemester(context, cookie, semesterId, TokenData.isVPN());
    if (semesterInfo.resp_code == 200) {
      return new Gson().fromJson(semesterInfo.content, Semester.class);
    }
    return null;
  }

  public static List<Semester> getAllClassTableSemester(Context context, String cookie) {
    HttpConnectionAndCode classTableIndex = Net.getClassTableIndex(context, cookie, TokenData.isVPN());
    if (classTableIndex.resp_code == 200) {
      Pattern pattern = Pattern.compile("var.?semesters.?=.?JSON\\.parse\\([.\n]?[^']*?'([^']*)'");
      Matcher matcher = pattern.matcher(classTableIndex.content);
      if (matcher.find()) {
        String semesters = "\"" + matcher.group(1) + "\"";
        semesters = new Gson().fromJson(semesters, String.class);
        return new Gson().fromJson(semesters, new TypeToken<List<Semester>>() {
        }.getType());
      }
    }
    return null;
  }

  /**
   * 获取当前学期
   *
   * @param semesters
   * @return
   */
  public static Semester getSemester(List<Semester> semesters) {
    if (semesters == null || semesters.isEmpty()) {
      return null;
    }
    long now = System.currentTimeMillis();
    Collections.sort(semesters, (a, b) -> a.getStartTime().compareTo(b.getStartTime()));
    for (Semester semester : semesters) {
      if (now >= semester.getStartTime() && now < semester.getEndTime() + 86400 * 1000L) {
        return semester;
      }
    }
    return semesters.get(semesters.size() - 1);
  }

  public static String getLabBridgeJWT(Context context, String cookie) {
    HttpConnectionAndCode labTableRes = Net.getLabBridgeJWT(context, cookie, TokenData.isVPN());
    if (labTableRes.resp_code / 100 == 3) {
      String Location = labTableRes.c.getHeaderField("location");
      Pattern pattern = Pattern.compile("token=(.*?)(?:&|$)");
      Matcher matcher = pattern.matcher(Location);
      if (matcher.find()) {
        return matcher.group(1);
      }
    }
    return null;
  }

  public static String getLabJWT(Context context, String cookie) {
    String EDUJWTToken = getLabBridgeJWT(context, cookie);
    if (EDUJWTToken == null) {
      return null;
    }
    HttpConnectionAndCode labTableRes = Net.getLabJWT(context, cookie, EDUJWTToken, TokenData.isVPN());
    if (labTableRes.resp_code / 100 == 2) {
      LabTableJWT labJWT = new Gson().fromJson(labTableRes.content, LabTableJWT.class);
      return labJWT.getToken();
    }
    return null;
  }

  public static Map<String, String> getLabLessonCode(Context context, String jwtToken, String cookie) {
    try {
      HttpConnectionAndCode labIndexRes = Net.getLabIndex(context, jwtToken, cookie, TokenData.isVPN());
      if (labIndexRes.resp_code == 200) {
        LabList labIndex = new Gson().fromJson(labIndexRes.content, LabList.class);
        return labIndex.toMap();
      }
    } catch (Exception ignore) {

    }
    return null;
  }

  public static List<CourseBean> getLabTableNew(Context context, String cookie, String startDate, String endDate) {
    try {
      String jwtToken = getLabJWT(context, cookie);
      if (jwtToken == null) {
        return null;
      }
      Map<String, String> labIndex = getLabLessonCode(context, jwtToken, cookie);
      HttpConnectionAndCode labTableRes = Net.getLabTableNew(context, jwtToken, cookie, startDate, endDate, TokenData.isVPN());
      if (labTableRes.resp_code == 200) {
        LabTableNew labTable = new Gson().fromJson(labTableRes.content, LabTableNew.class);
        return labTable.toCourseBeans(labIndex);
      } else {
        return null;
      }
    } catch (Exception ignore) {
      return null;
    }
  }

  public static List<ExamBean> getExamNew(Context context, String cookie) {
    GeneralData generalData = GeneralData.newInstance(context);
    HttpConnectionAndCode examArrange = Net.getExamArrange(context, cookie, TokenData.isVPN());
    if (examArrange.resp_code == 200) {
      Pattern pattern = Pattern.compile("studentExamInfoVms.?=.?(.+);$", Pattern.MULTILINE);
      Matcher matcher = pattern.matcher(examArrange.content);
      if (matcher.find()) {
        List<ExamBean> examBeanList = new ArrayList<>();
        String examInfoStr = matcher.group(1).replace("'", "\"");
        List<ExamInfoNew> examInfoList = new Gson().fromJson(examInfoStr, new TypeToken<List<ExamInfoNew>>() {
        }.getType());
        for (ExamInfoNew exam : examInfoList) {
          examBeanList.add(exam.toExamBean(generalData));
        }
        return examBeanList;
      }
    }
    return null;
  }

  public static String getExamScoreNewUrl(Context context, String cookie) {
    try {
      HttpConnectionAndCode examScoreUrlInfo = Net.getExamScoreUrlNew(context, cookie, TokenData.isVPN());
      if (examScoreUrlInfo.resp_code / 100 == 3) {
        String Location = examScoreUrlInfo.c.getHeaderField("location");
        String[] subPath = Location.split("/");
        return subPath[max(0, subPath.length - 1)];
      }
    } catch (Exception ignored) {

    }
    return "";
  }

  public static ExamScoreNew getExamScoreNew(Context context, String cookie) {
    try {
      String ExamScoreEndpointId = getExamScoreNewUrl(context, cookie);
      HttpConnectionAndCode examScoreInfo = Net.getExamScoreNew(context, cookie, ExamScoreEndpointId, TokenData.isVPN());
      if (examScoreInfo.resp_code == 200) {
        return new Gson().fromJson(examScoreInfo.content, ExamScoreNew.class);
      }
    } catch (Exception ignored) {
    }
    return null;
  }

  /**
   * 查询已选课程
   *
   * @param context context
   * @param cookie  cookie
   * @return 操作结果
   */
  public static List<SelectedCourseBean> getSelectedCourse(Context context, String cookie, int semseterid) {
    List<SelectedCourseBean> courseBeans = new ArrayList<>();
    try {
      HttpConnectionAndCode classTable = Net.getClassList(context, semseterid, cookie, TokenData.isVPN());
      if (classTable.resp_code == 200) {
        ClassList table = new Gson().fromJson(classTable.content, ClassList.class);
        List<ClassList.ClassInfo> maintable = table.lessons;
        for (ClassList.ClassInfo lesson : maintable) {
          try {
            SelectedCourseBean course = lesson.toSelectedCourseBean();
            if (course != null) {
              courseBeans.add(course);
            }
          } catch (Exception ignore) {

          }
        }
        return courseBeans;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

}
